package de.bomberman.bomb;

import com.jme3.app.Application;
import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioNode;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.effect.ParticleEmitter;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import de.bomberman.appstate.MainApp;
import de.bomberman.world.DefaultLevel;
import de.bomberman.world.FIELD_TYPE;
import de.bomberman.world.Field;
import de.bomberman.world.Player;
import factory.ParticleFactory;
import java.io.IOException;
import java.util.HashSet;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Mats
 */
public class Bomb implements Control {

    private Node bombNode;
    private RigidBodyControl physics;
    private Spatial bombSpatial;
    private final float bombRotatingSpeed = 1;
    private int explosionRange = 6;
    private Future future;
    private AssetManager assetManager;
    private MainApp app;
    // audio nodes
    private AudioNode audioExplosion;
    private AudioNode audioDropBomb;
    // Logger
    private static final Logger logger = Logger.getLogger(Bomb.class.getName());

    public Bomb(AssetManager assetManager, Vector3f location, Application app) {
        this.assetManager = assetManager;
        this.app = (MainApp) app;

        bombSpatial = assetManager.loadModel("Models/bomb/bomb.j3o");
        bombSpatial.scale(0.3f);
        bombSpatial.setShadowMode(RenderQueue.ShadowMode.Cast);
        bombSpatial.setLocalTranslation(location);

        // add rotate control
        bombSpatial.addControl(this);

        // setup the physics
        physics = new RigidBodyControl(0.0f);

        //bomb.addControl(physics);
        //physics.setPhysicsLocation();

        bombNode = new Node("Bomb Node");
        bombNode.attachChild(bombSpatial);


        // init the sound effects
        audioExplosion = new AudioNode(assetManager, "Sounds/explosion.wav", false);
        audioExplosion.setLooping(false);
        audioExplosion.setVolume(2);
        bombNode.attachChild(audioExplosion);

        audioDropBomb = new AudioNode(assetManager, "Sounds/dropBomb.wav", false);
        audioDropBomb.setLooping(false);
        audioDropBomb.setVolume(1);
        audioDropBomb.attachChild(audioDropBomb);
        audioDropBomb.playInstance();

    }

    public Node getBombNode() {
        return bombNode;
    }

    public RigidBodyControl getPhysics() {
        return physics;
    }

    @Override
    public Control cloneForSpatial(Spatial spatial) {
        return this;
    }

    @Override
    public void setSpatial(Spatial spatial) {
    }

    @Override
    public void update(float tpf) {
        bombSpatial.rotate(0, 0, tpf * bombRotatingSpeed);
        if (future == null) {
            future = MainApp.executor.submit(checkBombExplode);
        } else if (future != null) {
            if (future.isDone()) {

                future = null;
            } else if (future.isCancelled()) {
                future = null;
            }
        }
    }
    HashSet<Vector3f> destroyedBoxes;
    Vector3f playerLocation;
    Callable<Void> checkBombExplode = new Callable<Void>() {
        @Override
        public Void call() throws Exception {

            Thread.sleep(2500);
            app.enqueue(new Callable<Void>() {
                @Override
                public Void call() throws Exception {

                    int x = (int) bombSpatial.getLocalTranslation().getX();
                    int z = (int) bombSpatial.getLocalTranslation().getZ();

                    destroyedBoxes = new HashSet<>();

                    Vector3f location;

                    ParticleEmitter explode;
                    ParticleEmitter fire;

                    for (int i = x; i < x + explosionRange; i++) {

                        if (i < DefaultLevel.field.length) {
                            if (DefaultLevel.field[i][z].getType() == FIELD_TYPE.EMPTY
                                    || DefaultLevel.field[i][z].getType() == FIELD_TYPE.BOMB) {
                                location = new Vector3f(i, 1, z);
                                // if (DefaultLevel.field[i][z].getType() == FIELD_TYPE.BOMB) {
                                destroyedBoxes.add(location);
                                //  }
                                explode = ParticleFactory.getExplosion(assetManager, location);
                                fire = ParticleFactory.getFire(assetManager, location);
                                bombNode.attachChild(explode);
                                bombNode.attachChild(fire);
                            } else if (DefaultLevel.field[i][z].getType() == FIELD_TYPE.WOOD) {
                                location = new Vector3f(i, 1, z);
                                destroyedBoxes.add(location);
                                explode = ParticleFactory.getExplosion(assetManager, location);
                                fire = ParticleFactory.getFire(assetManager, location);
                                bombNode.attachChild(explode);
                                bombNode.attachChild(fire);
                                break;
                            } else {
                                break;
                            }
                        }
                    }

                    for (int i = x; i > x - explosionRange; i--) {
                        if (i >= 0) {
                            if (DefaultLevel.field[i][z].getType() == FIELD_TYPE.EMPTY
                                    || DefaultLevel.field[i][z].getType() == FIELD_TYPE.BOMB) {
                                location = new Vector3f(i, 1, z);
                                // if (DefaultLevel.field[i][z].getType() == FIELD_TYPE.BOMB) {
                                destroyedBoxes.add(location);
                                // }
                                explode = ParticleFactory.getExplosion(assetManager, location);
                                fire = ParticleFactory.getFire(assetManager, location);
                                bombNode.attachChild(explode);
                                bombNode.attachChild(fire);
                            } else if (DefaultLevel.field[i][z].getType() == FIELD_TYPE.WOOD) {
                                location = new Vector3f(i, 1, z);
                                destroyedBoxes.add(location);
                                explode = ParticleFactory.getExplosion(assetManager, location);
                                fire = ParticleFactory.getFire(assetManager, location);
                                bombNode.attachChild(explode);
                                bombNode.attachChild(fire);
                                break;
                            } else {
                                break;
                            }
                        }
                    }


                    for (int i = z; i < z + explosionRange; i++) {
                        if (i < DefaultLevel.field[x].length) {
                            if (DefaultLevel.field[x][i].getType() == FIELD_TYPE.EMPTY
                                    || DefaultLevel.field[x][i].getType() == FIELD_TYPE.BOMB) {
                                location = new Vector3f(x, 1, i);
                                // if (DefaultLevel.field[x][i].getType() == FIELD_TYPE.BOMB) {
                                destroyedBoxes.add(location);
                                // }
                                explode = ParticleFactory.getExplosion(assetManager, location);
                                fire = ParticleFactory.getFire(assetManager, location);
                                bombNode.attachChild(explode);
                                bombNode.attachChild(fire);
                            } else if (DefaultLevel.field[x][i].getType() == FIELD_TYPE.WOOD) {
                                location = new Vector3f(x, 1, i);
                                destroyedBoxes.add(location);
                                explode = ParticleFactory.getExplosion(assetManager, location);
                                fire = ParticleFactory.getFire(assetManager, location);
                                bombNode.attachChild(explode);
                                bombNode.attachChild(fire);
                                break;
                            } else {
                                break;
                            }
                        }
                    }

                    for (int i = z; i > z - explosionRange; i--) {
                        if (i >= 0) {
                            if (DefaultLevel.field[x][i].getType() == FIELD_TYPE.EMPTY
                                    || DefaultLevel.field[x][i].getType() == FIELD_TYPE.BOMB) {
                                location = new Vector3f(x, 1, i);
                                // if (DefaultLevel.field[x][i].getType() == FIELD_TYPE.BOMB) {
                                destroyedBoxes.add(location);
                                // }
                                explode = ParticleFactory.getExplosion(assetManager, location);
                                fire = ParticleFactory.getFire(assetManager, location);
                                bombNode.attachChild(explode);
                                bombNode.attachChild(fire);
                            } else if (DefaultLevel.field[x][i].getType() == FIELD_TYPE.WOOD) {
                                location = new Vector3f(x, 1, i);
                                destroyedBoxes.add(location);
                                explode = ParticleFactory.getExplosion(assetManager, location);
                                fire = ParticleFactory.getFire(assetManager, location);
                                bombNode.attachChild(explode);
                                bombNode.attachChild(fire);
                                break;
                            } else {
                                break;
                            }
                        }
                    }
                    playerLocation = Player.getCurrentLocation();
                    audioExplosion.playInstance();
                    return null;
                }
            });

            Thread.sleep(1000);
            app.enqueue(new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                    bombNode.detachAllChildren();
                    if (destroyedBoxes.contains(playerLocation)) {
                        System.out.println("DEAD on " + playerLocation);
                    }

                    for (Vector3f location : destroyedBoxes) {
                        Field field = DefaultLevel.field[(int) location.getX()][(int) location.getZ()];
                        if (field.getPhysics() != null) {
                            DefaultLevel.bulletAppState.getPhysicsSpace().remove(field.getPhysics());
                        }
                        field.setType(FIELD_TYPE.EMPTY);
                        Node obstacles = (Node) (DefaultLevel.levelNode.getChild("obstacles"));
                        if (field.getObstacle() != null) {
                            obstacles.detachChild(field.getObstacle());
                        }
                    }
                    return null;
                }
            });



            return null;
        }
    };

    @Override
    public void render(RenderManager rm, ViewPort vp) {
    }

    @Override
    public void write(JmeExporter ex) throws IOException {
    }

    @Override
    public void read(JmeImporter im) throws IOException {
    }
}
